{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Set working directory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "cwd = os.path.split(os.getcwd())\n",
    "if cwd[-1] == 'tutorials':\n",
    "    os.chdir('..')\n",
    "\n",
    "assert os.path.split(os.getcwd())[-1] == 'BRON'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Import modules"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import csv\n",
    "import json\n",
    "import statistics\n",
    "import time\n",
    "from memory_profiler import memory_usage\n",
    "from typing import Tuple, Set, List, Dict\n",
    "from path_search.path_search_BRON import main_attack\n",
    "from meta_analysis.find_riskiest_software import load_graph_network, riskiest_software"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# BRON-JSON"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "BRON-JSON is the JSON-based implementation of BRON. Run the next code cell to build BRON-JSON."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from download_threat_information.download_threat_data import _download_attack, _download_capec, _download_cwe, _download_cve, main\n",
    "from download_threat_information.parsing_scripts.parse_attack_tactic_technique import link_tactic_techniques\n",
    "from download_threat_information.parsing_scripts.parse_cve import parse_cve_file\n",
    "from download_threat_information.parsing_scripts.parse_capec_cwe import parse_capec_cwe_files\n",
    "from BRON.build_BRON import build_graph, BRON_PATH\n",
    "\n",
    "# Download threat information\n",
    "out_path = 'download_threat_information'\n",
    "cve_years = ['2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011',\n",
    "             '2012', '2013', '2014', '2015', '2016', '2017', '2018', '2019', '2020']\n",
    "main(cve_years)\n",
    "\n",
    "# Parse threat data\n",
    "filename = os.path.join(out_path, 'raw_enterprise_attack.json')\n",
    "link_tactic_techniques(filename, out_path)\n",
    "\n",
    "cve_path = os.path.join(out_path, 'raw_CVE.json.gz')\n",
    "save_path_file = \"cve_map_cpe_cwe_score.json\"\n",
    "save_file = os.path.join(out_path, save_path_file)\n",
    "parse_cve_file(cve_path, save_file)\n",
    "\n",
    "capec_file = os.path.join(out_path, 'raw_CAPEC.json')\n",
    "cwe_file = os.path.join(out_path, 'raw_CWE.zip')\n",
    "parse_capec_cwe_files(capec_file, cwe_file, save_path=out_path)\n",
    "\n",
    "# Build BRON\n",
    "BRON_folder_path = 'full_data/full_output_data'\n",
    "os.makedirs(BRON_folder_path, exist_ok=True)\n",
    "input_data_folder = 'download_threat_information'\n",
    "BRON_original_id_to_bron_id_path = os.path.join(BRON_folder_path, BRON_PATH)\n",
    "os.makedirs(BRON_original_id_to_bron_id_path, exist_ok=True)\n",
    "build_graph(BRON_folder_path, input_data_folder)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# BRON-Graph-DB"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "BRON-Graph-DB stores BRON in ArangoDB. Run the following code cell to connect to BRON-Graph-DB."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import arango\n",
    "\n",
    "SERVER_IP = 'bron.alfa.csail.mit.edu'\n",
    "USERNAME = 'guest'\n",
    "PASSWORD = 'guest'\n",
    "DB = 'BRON'\n",
    "client = arango.ArangoClient(hosts=f\"http://{SERVER_IP}:8529\")\n",
    "db = client.db(DB, username=USERNAME, password=PASSWORD, auth_method=\"basic\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Path search queries"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Two queries require searching graph paths. For them, the input is a CSV file of node IDs and the output is a CSV file with the IDs of nodes connected to each of the input nodes along an edge in BRON.\n",
    "\n",
    "The first query finds the threats connected to the top 10 CVEs which involves 390 nodes. The second query finds the threats and vulnerabilities connected to the top 25 CWEs which involves 322K nodes."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Query: Threats connected to top 10 CVEs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "top_10_cves_starting_file = 'tutorials/top_10_cves_starting_point.csv'\n",
    "top_10_cves_results_file = 'tutorials/top_10_cves_search_results.csv'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## BRON-JSON"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  13.152904987335205\n",
      "Max:  18.00979495048523\n",
      "Mean:  15.323847134908041\n",
      "SD:  1.7126983611103115\n"
     ]
    }
   ],
   "source": [
    "top_10_cves_times_BRON_JSON = []\n",
    "for i in range(30):\n",
    "    start_time = time.time()\n",
    "    main_attack(BRON_folder_path, top_10_cves_starting_file, top_10_cves_results_file, 'cve', length=False)\n",
    "    top_10_cves_times_BRON_JSON.append(time.time() - start_time)\n",
    "\n",
    "print(\"Min: \", min(top_10_cves_times_BRON_JSON))\n",
    "print(\"Max: \", max(top_10_cves_times_BRON_JSON))\n",
    "print(\"Mean: \", statistics.mean(top_10_cves_times_BRON_JSON))\n",
    "print(\"SD: \", statistics.stdev(top_10_cves_times_BRON_JSON))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  3029.9453125\n",
      "Max:  3196.4609375\n",
      "Mean:  3109.1575520833335\n",
      "SD:  72.61742354161925\n"
     ]
    }
   ],
   "source": [
    "def top_10_cves_path_search_BRON_JSON():\n",
    "    main_attack(BRON_folder_path, top_10_cves_starting_file, top_10_cves_results_file, 'cve', length=False)\n",
    "\n",
    "top_10_cves_mem_usages_BRON_JSON = []\n",
    "for i in range(30):\n",
    "    mem_usage = memory_usage(top_10_cves_path_search_BRON_JSON)\n",
    "    top_10_cves_mem_usages_BRON_JSON.append(max(mem_usage))\n",
    "\n",
    "print(\"Min: \", min(top_10_cves_mem_usages_BRON_JSON))\n",
    "print(\"Max: \", max(top_10_cves_mem_usages_BRON_JSON))\n",
    "print(\"Mean: \", statistics.mean(top_10_cves_mem_usages_BRON_JSON))\n",
    "print(\"SD: \", statistics.stdev(top_10_cves_mem_usages_BRON_JSON))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## BRON-Graph-DB"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "query_template_bron_id = \"\"\"\n",
    "FOR c IN {}\n",
    "    FILTER c.original_id == \"{}\"\n",
    "    RETURN c._key\n",
    "\"\"\"\n",
    "\n",
    "query_template_connections = \"\"\"\n",
    "WITH tactic, technique, capec, cwe, cve, cpe\n",
    "FOR vertex\n",
    "    IN 1..5\n",
    "    {} \"{}\"\n",
    "    GRAPH \"BRONGraph\"\n",
    "    OPTIONS {{ uniqueVertices: 'global', bfs: true }}\n",
    "    RETURN DISTINCT vertex._key\n",
    "\"\"\"\n",
    "\n",
    "def execute_query(query: str) -> Set[str]:\n",
    "    assert db.aql.validate(query)\n",
    "    cursor = db.aql.execute(query)\n",
    "    results = {_ for _ in cursor}\n",
    "    return results\n",
    "\n",
    "def convert_original_to_bron_id(data_type: str, original_ids: Tuple[str, ...]) -> Tuple[str, ...]:\n",
    "    bron_ids_list = []\n",
    "    for original_id in original_ids:\n",
    "        query_bron_id = query_template_bron_id.format(data_type, original_id)\n",
    "        results_bron_id = execute_query(query_bron_id)\n",
    "        bron_ids_list.append(results_bron_id.pop())\n",
    "    return tuple(bron_ids_list)\n",
    "\n",
    "def save_search_results_csv(connections_list: List[Dict[str, Set[str]]], results_file: str):\n",
    "    csv_columns = ['tactic', 'technique', 'capec', 'cwe', 'cve', 'cpe']\n",
    "    with open(results_file, 'w') as f:\n",
    "        writer = csv.DictWriter(f, fieldnames=csv_columns)\n",
    "        writer.writeheader()\n",
    "        for data in connections_list:\n",
    "            writer.writerow(data)\n",
    "\n",
    "def path_search_BRON_Graph_DB(data_type: str, starting_file: str, results_file: str, length: bool=False):\n",
    "    with open(starting_file) as f:\n",
    "        original_ids_list = [tuple(line) for line in csv.reader(f)]\n",
    "    original_ids = original_ids_list[0]\n",
    "    bron_ids = convert_original_to_bron_id(data_type, original_ids)\n",
    "    \n",
    "    directions = ('INBOUND', 'OUTBOUND')\n",
    "    connections_list = [] # List of dictionaries for each ID\n",
    "    for bron_id in bron_ids:\n",
    "        connections = {'tactic': set(), 'technique': set(), 'capec': set(), 'cwe': set(), 'cve': set(), 'cpe': set()}\n",
    "        connections[data_type].add(bron_id) # Add known connection of itself\n",
    "        full_bron_id = f'{data_type}/{bron_id}'\n",
    "        \n",
    "        for direction in directions:\n",
    "            query_connections = query_template_connections.format(direction, full_bron_id)\n",
    "            results_connections = execute_query(query_connections)\n",
    "            for result in results_connections:\n",
    "                result_split = result.split('_')\n",
    "                connections[result_split[0]].add(result)\n",
    "\n",
    "        if length: # Store number of data types instead of IDs\n",
    "            connections_count = dict()\n",
    "            for data_type_key, entries in connections.items():\n",
    "                connections_count[data_type_key] = len(entries)\n",
    "            connections_list.append(connections_count)\n",
    "        else:\n",
    "            connections_list.append(connections)\n",
    "    \n",
    "    save_search_results_csv(connections_list, results_file)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  4.139862060546875\n",
      "Max:  6.321671962738037\n",
      "Mean:  4.903802156448364\n",
      "SD:  0.7657081047300861\n"
     ]
    }
   ],
   "source": [
    "top_10_cves_times_BRON_Graph_DB = []\n",
    "for i in range(30):\n",
    "    start_time = time.time()\n",
    "    path_search_BRON_Graph_DB('cve', top_10_cves_starting_file, top_10_cves_results_file)\n",
    "    top_10_cves_times_BRON_Graph_DB.append(time.time() - start_time)\n",
    "\n",
    "print(\"Min: \", min(top_10_cves_times_BRON_Graph_DB))\n",
    "print(\"Max: \", max(top_10_cves_times_BRON_Graph_DB))\n",
    "print(\"Mean: \", statistics.mean(top_10_cves_times_BRON_Graph_DB))\n",
    "print(\"SD: \", statistics.stdev(top_10_cves_times_BRON_Graph_DB))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  325.3359375\n",
      "Max:  325.57421875\n",
      "Mean:  325.3795572916667\n",
      "SD:  0.09544102076156989\n"
     ]
    }
   ],
   "source": [
    "def top_10_cves_path_search_BRON_Graph_DB():\n",
    "    path_search_BRON_Graph_DB('cve', top_10_cves_starting_file, top_10_cves_results_file)\n",
    "    \n",
    "top_10_cves_mem_usages_BRON_Graph_DB = []\n",
    "for i in range(30):\n",
    "    mem_usage = memory_usage(top_10_cves_path_search_BRON_Graph_DB)\n",
    "    top_10_cves_mem_usages_BRON_Graph_DB.append(max(mem_usage))\n",
    "\n",
    "print(\"Min: \", min(top_10_cves_mem_usages_BRON_Graph_DB))\n",
    "print(\"Max: \", max(top_10_cves_mem_usages_BRON_Graph_DB))\n",
    "print(\"Mean: \", statistics.mean(top_10_cves_mem_usages_BRON_Graph_DB))\n",
    "print(\"SD: \", statistics.stdev(top_10_cves_mem_usages_BRON_Graph_DB))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Query: Threats and vulnerabilities connected to top 25 CWEs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "top_25_cwes_starting_file = 'tutorials/top_25_cwes_starting_point.csv'\n",
    "top_25_cwes_results_file = 'tutorials/top_25_cwes_search_results.csv'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## BRON-JSON"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  13.084337949752808\n",
      "Max:  14.7556631565094\n",
      "Mean:  13.598588188489279\n",
      "SD:  0.5982005094070681\n"
     ]
    }
   ],
   "source": [
    "top_25_cwes_times_BRON_JSON = []\n",
    "for i in range(30):\n",
    "    start_time = time.time()\n",
    "    main_attack(BRON_folder_path, top_25_cwes_starting_file, top_25_cwes_results_file, 'cwe', length=False)\n",
    "    top_25_cwes_times_BRON_JSON.append(time.time() - start_time)\n",
    "\n",
    "print(\"Min: \", min(top_25_cwes_times_BRON_JSON))\n",
    "print(\"Max: \", max(top_25_cwes_times_BRON_JSON))\n",
    "print(\"Mean: \", statistics.mean(top_25_cwes_times_BRON_JSON))\n",
    "print(\"SD: \", statistics.stdev(top_25_cwes_times_BRON_JSON))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  2905.5390625\n",
      "Max:  3054.42578125\n",
      "Mean:  3010.9264322916665\n",
      "SD:  61.050130059064394\n"
     ]
    }
   ],
   "source": [
    "def top_25_cwes_path_search_BRON_JSON():\n",
    "    main_attack(BRON_folder_path, top_25_cwes_starting_file, top_25_cwes_results_file, 'cwe', length=False)\n",
    "\n",
    "top_25_cwes_mem_usages_BRON_JSON = []\n",
    "for i in range(30):\n",
    "    mem_usage = memory_usage(top_25_cwes_path_search_BRON_JSON)\n",
    "    top_25_cwes_mem_usages_BRON_JSON.append(max(mem_usage))\n",
    "\n",
    "print(\"Min: \", min(top_25_cwes_mem_usages_BRON_JSON))\n",
    "print(\"Max: \", max(top_25_cwes_mem_usages_BRON_JSON))\n",
    "print(\"Mean: \", statistics.mean(top_25_cwes_mem_usages_BRON_JSON))\n",
    "print(\"SD: \", statistics.stdev(top_25_cwes_mem_usages_BRON_JSON))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## BRON-Graph-DB"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  27.932520866394043\n",
      "Max:  36.45831918716431\n",
      "Mean:  33.20283730824789\n",
      "SD:  3.1230440321029898\n"
     ]
    }
   ],
   "source": [
    "top_25_cwes_times_BRON_Graph_DB = []\n",
    "for i in range(30):\n",
    "    start_time = time.time()\n",
    "    path_search_BRON_Graph_DB('cwe', top_25_cwes_starting_file, top_25_cwes_results_file)\n",
    "    top_25_cwes_times_BRON_Graph_DB.append(time.time() - start_time)\n",
    "\n",
    "print(\"Min: \", min(top_25_cwes_times_BRON_Graph_DB))\n",
    "print(\"Max: \", max(top_25_cwes_times_BRON_Graph_DB))\n",
    "print(\"Mean: \", statistics.mean(top_25_cwes_times_BRON_Graph_DB))\n",
    "print(\"SD: \", statistics.stdev(top_25_cwes_times_BRON_Graph_DB))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  351.984375\n",
      "Max:  354.0625\n",
      "Mean:  353.3326822916667\n",
      "SD:  0.8012457367321904\n"
     ]
    }
   ],
   "source": [
    "def top_25_cwes_path_search_BRON_Graph_DB():\n",
    "    path_search_BRON_Graph_DB('cwe', top_25_cwes_starting_file, top_25_cwes_results_file)\n",
    "\n",
    "top_25_cwes_mem_usages_BRON_Graph_DB = []\n",
    "for i in range(30):\n",
    "    mem_usage = memory_usage(top_25_cwes_path_search_BRON_Graph_DB)\n",
    "    top_25_cwes_mem_usages_BRON_Graph_DB.append(max(mem_usage))\n",
    "\n",
    "print(\"Min: \", min(top_25_cwes_mem_usages_BRON_Graph_DB))\n",
    "print(\"Max: \", max(top_25_cwes_mem_usages_BRON_Graph_DB))\n",
    "print(\"Mean: \", statistics.mean(top_25_cwes_mem_usages_BRON_Graph_DB))\n",
    "print(\"SD: \", statistics.stdev(top_25_cwes_mem_usages_BRON_Graph_DB))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Query: Riskiest software"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This query outputs the Affected Product Configuration with the highest sum of CVSS scores for connected Vulnerabilities, which involves 2,453K nodes."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## BRON-JSON"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  19.32332491874695\n",
      "Max:  41.42757821083069\n",
      "Mean:  25.214418013890583\n",
      "SD:  8.203344986935523\n"
     ]
    }
   ],
   "source": [
    "riskiest_software_times_BRON_JSON = []\n",
    "for i in range(30):\n",
    "    start_time = time.time()\n",
    "    graph = load_graph_network(f'{BRON_folder_path}/BRON.json')\n",
    "    riskiest_software(graph)\n",
    "    riskiest_software_times_BRON_JSON.append(time.time() - start_time)\n",
    "\n",
    "print(\"Min: \", min(riskiest_software_times_BRON_JSON))\n",
    "print(\"Max: \", max(riskiest_software_times_BRON_JSON))\n",
    "print(\"Mean: \", statistics.mean(riskiest_software_times_BRON_JSON))\n",
    "print(\"SD: \", statistics.stdev(riskiest_software_times_BRON_JSON))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  3558.15234375\n",
      "Max:  4172.609375\n",
      "Mean:  3738.2493489583335\n",
      "SD:  228.8380976618797\n"
     ]
    }
   ],
   "source": [
    "def riskiest_software_BRON_JSON():\n",
    "    graph = load_graph_network(f'{BRON_folder_path}/BRON.json')\n",
    "    riskiest_software(graph)\n",
    "\n",
    "riskiest_software_mem_usages_BRON_JSON = []\n",
    "for i in range(30):\n",
    "    max_mem_usage = max(memory_usage(riskiest_software_BRON_JSON))\n",
    "    riskiest_software_mem_usages_BRON_JSON.append(max_mem_usage)\n",
    "\n",
    "print(\"Min: \", min(riskiest_software_mem_usages_BRON_JSON))\n",
    "print(\"Max: \", max(riskiest_software_mem_usages_BRON_JSON))\n",
    "print(\"Mean: \", statistics.mean(riskiest_software_mem_usages_BRON_JSON))\n",
    "print(\"SD: \", statistics.stdev(riskiest_software_mem_usages_BRON_JSON))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## BRON-Graph-DB"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "query_riskiest_software = \"\"\"\n",
    "WITH cve, cpe\n",
    "FOR c in cpe\n",
    "    LET cvss_scores = (\n",
    "        FOR vertex\n",
    "            IN 1..1\n",
    "            INBOUND c._id\n",
    "            CveCpe\n",
    "            OPTIONS { uniqueVertices: 'global', bfs: true }\n",
    "            RETURN vertex.metadata.weight\n",
    "    )\n",
    "    RETURN { cpe_node: c.original_id, cvss_score: SUM(cvss_scores) }\n",
    "\"\"\"\n",
    "\n",
    "def execute_query(query: str) -> Set[str]:\n",
    "    assert db.aql.validate(query)\n",
    "    cursor = db.aql.execute(query)\n",
    "    results = [_ for _ in cursor]\n",
    "    return results\n",
    "\n",
    "def riskiest_software_BRON_Graph_DB():\n",
    "    results_riskiest_software = execute_query(query_riskiest_software)\n",
    "    highest_software = set()\n",
    "    highest_score = -1\n",
    "    for cpe_cvss_dict in results_riskiest_software:\n",
    "        cpe_node = cpe_cvss_dict['cpe_node']\n",
    "        cvss_score = cpe_cvss_dict['cvss_score']\n",
    "        if cvss_score > highest_score:\n",
    "            highest_software = {cpe_node}\n",
    "            highest_score = cvss_score\n",
    "        elif cvss_score == highest_score:\n",
    "            highest_software.add(cpe_node)\n",
    "    return highest_software, highest_score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  24.950159072875977\n",
      "Max:  35.09775495529175\n",
      "Mean:  27.96189483006795\n",
      "SD:  3.613808536195016\n"
     ]
    }
   ],
   "source": [
    "riskiest_software_times_BRON_Graph_DB = []\n",
    "for i in range(30):\n",
    "    start_time = time.time()\n",
    "    riskiest_software_BRON_Graph_DB()\n",
    "    riskiest_software_times_BRON_Graph_DB.append(time.time() - start_time)\n",
    "\n",
    "print(\"Min: \", min(riskiest_software_times_BRON_Graph_DB))\n",
    "print(\"Max: \", max(riskiest_software_times_BRON_Graph_DB))\n",
    "print(\"Mean: \", statistics.mean(riskiest_software_times_BRON_Graph_DB))\n",
    "print(\"SD: \", statistics.stdev(riskiest_software_times_BRON_Graph_DB))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Min:  1201.890625\n",
      "Max:  1292.265625\n",
      "Mean:  1217.1516927083333\n",
      "SD:  36.799029712048245\n"
     ]
    }
   ],
   "source": [
    "riskiest_software_mem_usages_BRON_Graph_DB = []\n",
    "for i in range(30):\n",
    "    max_mem_usage = max(memory_usage(riskiest_software_BRON_Graph_DB))\n",
    "    riskiest_software_mem_usages_BRON_Graph_DB.append(max_mem_usage)\n",
    "\n",
    "print(\"Min: \", min(riskiest_software_mem_usages_BRON_Graph_DB))\n",
    "print(\"Max: \", max(riskiest_software_mem_usages_BRON_Graph_DB))\n",
    "print(\"Mean: \", statistics.mean(riskiest_software_mem_usages_BRON_Graph_DB))\n",
    "print(\"SD: \", statistics.stdev(riskiest_software_mem_usages_BRON_Graph_DB))"
   ]
  }
 ],
 "metadata": {
  "@webio": {
   "lastCommId": null,
   "lastKernelId": null
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
